/* IMPLEMENATION OF K-MEANS FOR PURE DATA: UNSUPERVISIONED MACHINE LEARNING ALGORITHM
 * FOR DATA CLUSTERIZATION.
 *  
 *  by Adriano Monteiro, december, 27, 2012. contact: monteiro.adc@gmaill.com
 *  
 */

#include "m_pd.h"
#include <stdlib.h>
#include <math.h>
#include <fftw3.h>



static t_class *fftw_class;

typedef struct _fftw {
        t_object x_obj;
        
  
        // leitura da array source
        t_word *src_vec;
        t_symbol *src_arrayname;
    	int src_array_points;
    	
        // leitura da array destine
        t_word *dst_re_vec;
        t_symbol *dst_re_arrayname;
       	int dst_re_array_points;
       	
       	t_word *dst_im_vec;
       	t_symbol *dst_im_arrayname;
       	int dst_im_array_points;
                
       
}t_fftw;

/*********************** INTERNAL FUNCTIONS  *******************************/




/******************* BANG MESSAGE ***************************************/

void fftw_bang(t_fftw *x) {
	
	int i;
	fftw_complex *in, *out;
	t_garray *a, *b, *c;
	fftw_plan p;

	// access array
	if(!(a = (t_garray *)pd_findbyclass(x->src_arrayname, garray_class)))
	  	pd_error(x, "%s: no such array", x->src_arrayname->s_name);
	else if(!garray_getfloatwords(a, &x->src_array_points, &x->src_vec))
		pd_error(x, "%s: bad template for wav2aud", x->src_arrayname->s_name);	
	
	if(!(b = (t_garray *)pd_findbyclass(x->dst_re_arrayname, garray_class)))
		pd_error(x, "%s: no such array", x->dst_re_arrayname->s_name);
	else if(!garray_getfloatwords(b, &x->dst_re_array_points, &x->dst_re_vec))
		pd_error(x, "%s: bad template for wav2aud", x->dst_re_arrayname->s_name);		
	
	if(!(c = (t_garray *)pd_findbyclass(x->dst_im_arrayname, garray_class)))
		pd_error(x, "%s: no such array", x->dst_im_arrayname->s_name);
	else if(!garray_getfloatwords(c, &x->dst_im_array_points, &x->dst_im_vec))
		pd_error(x, "%s: bad template for wav2aud", x->dst_im_arrayname->s_name);	
	  		 
	
	in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * x->src_array_points);
	out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * x->src_array_points);
	
	
	
	for(i=0; i < x->src_array_points; i++){ 
		in[i][0] = (double) x->src_vec[i].w_float;
		in[i][1] = 0;
	}

    p = fftw_plan_dft_1d(x->src_array_points, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
      
    fftw_execute(p); 
   
    for(i=0; i < x->src_array_points; i++)x->dst_re_vec[i].w_float = (float) out[i][0];
    for(i=0; i < x->src_array_points; i++)x->dst_im_vec[i].w_float = (float) out[i][1];
    
	garray_redraw(b);
	garray_redraw(c);
	
	fftw_destroy_plan(p);  
	fftw_free(in); fftw_free(out);		
	
   
}

/****************************** DATA ACESS METHOD **********************************/


		
/************************** OBJECT CREATION AND SETUP *************************************/

void *fftw_new(t_symbol *s, int argc, t_atom *argv){
     t_fftw *x = (t_fftw *)pd_new(fftw_class);
     
  // acesso a array copiado do tabletool do brent 	
	t_garray *a, *b, *c;
 		
  	if(atom_getsymbol(argv)){
  		x->src_arrayname = atom_getsymbol(argv);

  		if(!(a = (t_garray *)pd_findbyclass(x->src_arrayname, garray_class)))
  		        pd_error(x, "%s: no such array", x->src_arrayname->s_name);
  		 else if(!garray_getfloatwords(a, &x->src_array_points, &x->src_vec))
  		    	pd_error(x, "%s: bad template for wav2aud", x->src_arrayname->s_name);	
  		}
  		else
  			post("WARNING: no array specified.");
  		
  	if(atom_getsymbol(argv+1)){
  		 x->dst_re_arrayname = atom_getsymbol(argv+1);

  		 if(!(b = (t_garray *)pd_findbyclass(x->dst_re_arrayname, garray_class)))
  		        pd_error(x, "%s: no such array", x->dst_re_arrayname->s_name);
  		 else if(!garray_getfloatwords(b, &x->dst_re_array_points, &x->dst_re_vec))
  		     	pd_error(x, "%s: bad template for wav2aud", x->dst_re_arrayname->s_name);	
  		 }
  		 else
  		 		post("WARNING: no array specified.");
  	
	if(atom_getsymbol(argv+2)){
  		 x->dst_im_arrayname = atom_getsymbol(argv+2);

  		 if(!(c = (t_garray *)pd_findbyclass(x->dst_im_arrayname, garray_class)))
  		        pd_error(x, "%s: no such array", x->dst_im_arrayname->s_name);
  		 else if(!garray_getfloatwords(c, &x->dst_im_array_points, &x->dst_im_vec))
  		     	pd_error(x, "%s: bad template for wav2aud", x->dst_im_arrayname->s_name);	
  		 }
  		 else
  		 		post("WARNING: no array specified.");
  	
 
     return (void *) x;
}

    
void fftw_setup(void) {
	 fftw_class = class_new(gensym("fftw"), (t_newmethod)fftw_new, 
     0, sizeof(t_fftw), CLASS_DEFAULT, A_GIMME, 0);
      
    class_addbang(fftw_class, fftw_bang);
 
}

